home *** CD-ROM | disk | FTP | other *** search
- UNIT AE1 ;
-
- {$R-}
- {$B-}
- {$I-}
- {$S+}
- {$V-}
-
- {-----------------------------------------------------------------------------}
- { This unit contains all basic procedures }
- {-----------------------------------------------------------------------------}
-
- INTERFACE
-
- USES Crt, Dos, AE0 ;
-
- FUNCTION UpperCase (S : STRING) : STRING ;
- FUNCTION WordToString (Num : WORD ; Len : INTEGER) : STRING ;
- FUNCTION Wildcarded (Name : PathStr) : BOOLEAN ;
- FUNCTION Exists (FileName : PathStr) : BOOLEAN ;
- PROCEDURE MoveToScreen (VAR Source, Dest ; Len : WORD) ;
- PROCEDURE MoveFromScreen (VAR Source, Dest ; Len : WORD) ;
- PROCEDURE SaveArea (X1, Y1, X2, Y2 : WORD ; VAR MemPtr : ScreenBlockPtr) ;
- PROCEDURE RestoreArea (X1, Y1, X2, Y2 : WORD ; VAR MemPtr : ScreenBlockPtr) ;
- FUNCTION Grow (Index : WORD ; Chars : WORD) : BOOLEAN ;
- PROCEDURE Shrink (Index : WORD ; Chars : WORD) ;
- FUNCTION GetCursor : BYTE ;
- PROCEDURE SetCursor (Cursor : BYTE) ;
- PROCEDURE CursorTo (X, Y : BYTE) ;
- PROCEDURE WarningBeep ;
- FUNCTION ReadKeyNr : WORD ;
- PROCEDURE SetBottomLine (LineText : STRING) ;
- PROCEDURE Message (Contents : STRING) ;
- PROCEDURE ErrorMessage (ErrorNr : BYTE) ;
- PROCEDURE Pause ;
- PROCEDURE CheckDiskError ;
- PROCEDURE PutFrame (X1, Y1, X2, Y2 : BYTE ; Border : STRING) ;
- PROCEDURE ClearArea (X1, Y1, X2, Y2 : BYTE) ;
- PROCEDURE ClearCurrentWs ;
- PROCEDURE ClearKeyBuffer ;
- PROCEDURE CheckEsc ;
- PROCEDURE CreateHistory (VAR Hp : HistPtr ; LineLen : BYTE) ;
- PROCEDURE AddToHistory (Hp : HistPtr ; S : STRING) ;
- FUNCTION CurrentHistLine (Hp : HistPtr) : STRING ;
- FUNCTION NextHistLine (Hp : HistPtr) : STRING ;
- FUNCTION PrevHistLine (Hp : HistPtr) : STRING ;
- FUNCTION LeftMargin (VAR P : Position) : WORD ;
- {$IFDEF DEVELOP }
- PROCEDURE GetMem (VAR P : pointer ; Size : WORD ) ;
- {$ENDIF }
-
- IMPLEMENTATION
-
- {-----------------------------------------------------------------------------}
- { Converts all lower case letters in a string to upper case. }
- {-----------------------------------------------------------------------------}
-
- FUNCTION UpperCase (S : STRING) : STRING ;
-
- VAR Counter : WORD ;
-
- BEGIN
- FOR Counter := 1 TO LENGTH (S) DO S [Counter] := UPCASE (S [Counter]) ;
- UpperCase := S ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Converts an expression of type word to a string }
- { if Len < 0 then string is adjusted to the left; string length is <Len> }
- { if Len > 0 then string is adjusted to the right; string length is <-Len> }
- { if Len = 0 then string is not adjusted; string has minimum length }
- {-----------------------------------------------------------------------------}
-
- FUNCTION WordToString (Num : WORD ; Len : INTEGER) : STRING ;
-
- VAR S : STRING [5] ;
-
- BEGIN
- IF Len > 0
- THEN STR (Num : Len, S)
- ELSE BEGIN
- STR (Num, S) ;
- Len := - Len ;
- IF (Len > 0) AND (LENGTH (S) < Len)
- THEN BEGIN
- FILLCHAR (S [LENGTH (S) + 1], Len - LENGTH (S), ' ') ;
- S [0] := CHR (Len) ;
- END ;
- END ;
- WordToString := S ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Deletes all spaces on the left of a string. }
- {-----------------------------------------------------------------------------}
-
- FUNCTION TrimLeft (S : STRING) : STRING ;
-
- BEGIN
- WHILE (LENGTH (S) > 0) AND (S [1] = ' ') DO DELETE (S, 1, 1) ;
- TrimLeft := S ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Indicates whether a filename contains wildcard characters }
- {-----------------------------------------------------------------------------}
-
- FUNCTION Wildcarded (Name : PathStr) : BOOLEAN ;
-
- BEGIN
- Wildcarded := (POS ('*', Name) <> 0) OR (POS ('?', Name) <> 0) ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Returns True if the file <FileName> exists, False otherwise. }
- {-----------------------------------------------------------------------------}
-
- FUNCTION Exists (FileName : PathStr) : BOOLEAN ;
-
- VAR SR : SearchRec ;
-
- BEGIN
- FINDFIRST (FileName, ReadOnly + Hidden + SysFile, SR) ;
- Exists := (DosError = 0) AND (NOT Wildcarded (Filename) ) ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Moves <Len> bytes of memory to screen memory. }
- { From the TCALC spreadsheet program delivered with every copy of Turbo }
- { Pascal 5.5 }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE MoveToScreen (VAR Source, Dest ; Len : WORD) ;
-
- EXTERNAL ;
-
- {-----------------------------------------------------------------------------}
- { Moves <Len> bytes of screen memory to memory. }
- { From the TCALC spreadsheet program delivered with every copy of Turbo }
- { Pascal 5.5 }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE MoveFromScreen (VAR Source, Dest ; Len : WORD) ;
-
- EXTERNAL ;
-
- {$L TCMVSMEM.OBJ }
-
- {-----------------------------------------------------------------------------}
- { Saves the contents of a rectangular part of the screen to memory. }
- { Upper left corner is (X1,Y1), lower right is (X2,Y2) }
- { Also claims the amount of memory needed. }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE SaveArea (X1, Y1, X2, Y2 : WORD ; VAR MemPtr : ScreenBlockPtr) ;
-
- VAR LineLen : BYTE;
- Index : WORD;
- Counter : BYTE;
-
- BEGIN
- LineLen := X2 - X1 + 1;
- GETMEM (POINTER(MemPtr), LineLen * (Y2 - Y1 + 1) * 2) ;
- Index := 1 ;
- FOR Counter := Y1 TO Y2 DO
- BEGIN
- MoveFromScreen (DisplayPtr^ [Counter, X1], MemPtr^ [Index], LineLen * 2);
- INC (Index, LineLen)
- END;
- END;
-
- {-----------------------------------------------------------------------------}
- { Reverse of SaveArea }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE RestoreArea (X1, Y1, X2, Y2 : WORD ; VAR MemPtr : ScreenBlockPtr) ;
-
- VAR LineLen : BYTE;
- Index : WORD;
- Counter : BYTE;
-
- BEGIN
- LineLen := X2 - X1 + 1;
- Index := 1;
- FOR Counter := Y1 TO Y2 DO
- BEGIN
- MoveToScreen (MemPtr^ [Index], DisplayPtr^ [Counter, X1], LineLen * 2);
- INC (Index, LineLen)
- END;
- FREEMEM (MemPtr, LineLen * (Y2 - Y1 + 1) * 2) ;
- END;
-
- {-----------------------------------------------------------------------------}
- { Expands the text in the buffer of the current workspace at position }
- { <Index> by <Chars> characters. Function result is False if there is not }
- { enough space left, True otherwise. }
- { Index values of Mark and in position stack are adapted }
- {-----------------------------------------------------------------------------}
-
- FUNCTION Grow (Index : WORD ; Chars : WORD) : BOOLEAN ;
-
- VAR Counter : BYTE ;
-
- BEGIN
- WITH CurrentWs DO
- IF Chars > (WsBufSize - BufferSize)
- THEN BEGIN
- { not enough space }
- ErrorMessage (1) ;
- Grow := FALSE ;
- END
- ELSE BEGIN
- { move rest of text forward }
- MOVE (Buffer^ [Index], Buffer^ [Index + Chars], BufferSize - Index + 1) ;
- INC (BufferSize, Chars) ;
- { adapt Mark and position stack }
- IF MARK >= Index THEN INC (MARK, Chars) ;
- FOR Counter := 1 TO PosStackpointer DO
- BEGIN
- IF PosStack [Counter] >= Index
- THEN INC (PosStack [Counter], Chars) ;
- END ;
- ChangesMade := TRUE ;
- Grow := TRUE ;
- END ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Deletes <Chars> characters from the buffer in the current workspace, }
- { starting on position <Index>. }
- { Index values of Mark and in position stack are adapted }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE Shrink (Index : WORD ; Chars : WORD) ;
-
- VAR Counter : WORD ;
-
- BEGIN
- WITH CurrentWs DO
- BEGIN
- { move rest of text backward }
- MOVE (Buffer^ [Index + Chars], Buffer^ [Index], BufferSize - (Index + Chars) + 1) ;
- DEC (BufferSize, Chars) ;
- { adapt Mark }
- IF (MARK >= Index)
- THEN BEGIN
- IF (MARK < (Index + Chars) )
- THEN MARK := Inactive
- ELSE DEC (MARK, Chars) ;
- END ;
- { adapt position stack }
- FOR Counter := 1 TO PosStackpointer DO
- IF (PosStack [Counter] >= Index)
- THEN BEGIN
- IF (PosStack [Counter] < (Index + Chars) )
- THEN PosStack [Counter] := Index
- ELSE DEC (PosStack [Counter], Chars) ;
- END ;
- ChangesMade := TRUE ;
- END ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Returns the current cursor type }
- {-----------------------------------------------------------------------------}
-
- FUNCTION GetCursor : BYTE ;
-
- VAR Reg : REGISTERS ;
-
- BEGIN
- WITH Reg DO
- BEGIN
- AH := 3 ;
- BH := 0 ;
- { call BIOS interrupt }
- INTR ($10, Reg) ;
- CASE CX OF
- $0607, $0B0C : GetCursor := UnderLineCursor ;
- $0507, $090C : GetCursor := HalfBlockCursor ;
- $0807, $0D0C : GetCursor := BlockCursor ;
- $2000 : GetCursor := Inactive ;
- $2001 : GetCursor := NoBlinkCursor ;
- ELSE GetCursor := UnderLineCursor ;
- END ; { of case }
- END ; { of with }
- END ;
-
- {-----------------------------------------------------------------------------}
- { Sets a new cursor }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE SetCursor (Cursor : BYTE) ;
-
- VAR Reg : REGISTERS ;
- ScrEl : ScreenElement ;
-
- BEGIN
- WITH Reg DO
- BEGIN
- AH := 1 ;
- BH := 0 ;
- { monochrome and color cards require different settings for cursor shape }
- CASE Cursor OF
- Inactive : CX := $2000 ;
- UnderLineCursor : IF Colorcard THEN CX := $0607 ELSE CX := $0B0C ;
- HalfBlockCursor : IF Colorcard THEN CX := $0507 ELSE CX := $090C;
- BlockCursor : IF Colorcard THEN CX := $0807 ELSE CX := $0D0C ;
- NoBlinkCursor : CX := $2001 ;
- END ; { of case }
- { call BIOS interrupt }
- INTR ($10, Reg) ;
- END ; { with }
- IF Cursor = NoBlinkCursor
- THEN BEGIN
- { put NoBlinkCursor on new position }
- ScrEl := ScreenElement (DisplayPtr^ [WHEREY, WHEREX]) ;
- { set cursor attribute }
- WITH ScreenColorArray [Config.Setup.ScreenColors] DO
- IF WHEREY = LinesOnScreen
- THEN ScrEl.Attribute := CursorAttr
- ELSE ScrEl.Attribute := StatusCursorAttr ;
- DisplayPtr^ [WHEREY, WHEREX] := WORD (ScrEl) ;
- END ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Positions the cursor at (X,Y) }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE CursorTo (X, Y : BYTE) ;
-
- VAR ScrEl : ScreenElement ;
-
- BEGIN
- GOTOXY (X, Y) ;
- IF Config.Setup.CursorType = NoBlinkCursor
- THEN BEGIN
- { put NoBlinkCursor on new position }
- ScrEl := ScreenElement (DisplayPtr^ [Y, X]) ;
- { set cursor attribute }
- WITH ScreenColorArray [Config.Setup.ScreenColors] DO
- IF WHEREY = LinesOnScreen
- THEN ScrEl.Attribute := StatusCursorAttr
- ELSE ScrEl.Attribute := CursorAttr ;
- DisplayPtr^ [Y, X] := WORD (ScrEl) ;
- END ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Produces a low beep trough the speaker, unless inhibited by Setup }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE WarningBeep ;
-
- BEGIN
- IF Config.Setup.SoundBell
- THEN BEGIN
- SOUND (110) ;
- DELAY (100) ;
- NOSOUND ;
- END ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Waits until a key on the keyboard is pressed and returns its key number. }
- { Control keys (cursor keys, function keys etc.) are translated to numbers }
- { above 255. }
- {-----------------------------------------------------------------------------}
-
- FUNCTION ReadKeyNr : WORD ;
-
- VAR Regs : REGISTERS ;
-
- BEGIN
- WITH Regs DO
- BEGIN
- AH := 0 ;
- INTR ($16, Regs) ;
- { AL now contains the ASCII value of the key, AH the scan code }
- CASE AL OF
- 0 : IF AH = 3 THEN ReadKeyNr := 0 { ^@ }
- ELSE ReadKeyNr := 256 + AH ;
- 8 : IF AH = 14 THEN ReadKeyNr := BkspKey
- ELSE ReadKeyNr := 8 ; { ^H }
- 9 : IF AH = 15 THEN ReadKeyNr := TabKey
- ELSE ReadKeyNr := 9 ; { ^I }
- 10 : IF AH = 28 THEN ReadKeyNr := CtrlReturnKey
- ELSE ReadKeyNr := 10 ; { ^J }
- 13 : IF AH = 28 THEN ReadKeyNr := ReturnKey
- ELSE ReadKeyNr := 13 ; { ^M }
- 27 : IF AH = 1 THEN ReadKeyNr := EscapeKey
- ELSE ReadKeyNr := 27 ; { ^[ }
- ELSE ReadKeyNr := AL ;
- END ; { of case }
- END ; { of with }
- END ;
-
- {-----------------------------------------------------------------------------}
- { Puts a line of text on the last line of the screen. }
- { Writes directly into video memory. }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE SetBottomLine (LineText : STRING) ;
-
- VAR ScrEl : ScreenElement ;
- ScrElPtr : ScreenElementPtr ;
- Col : BYTE ;
-
- BEGIN
- ScrElPtr := ScreenElementPtr (StatusLinePtr) ;
- { set attribute }
- ScrEl.Attribute := ScreenColorArray [Config.Setup.ScreenColors].StatusAttr ;
- { fill first part of status line with LineText }
- FOR Col := 1 TO LENGTH (LineText) DO
- BEGIN
- ScrEl.Contents := LineText [Col] ;
- ScrElPtr.Ref^ := ScrEl ;
- INC (ScrElPtr.OFS, 2) ;
- END ;
- { fill rest of status line with spaces }
- ScrEl.Contents := ' ' ;
- FOR Col := (LENGTH (LineText) + 1) TO ColsOnScreen DO
- BEGIN
- ScrElPtr.Ref^ := ScrEl ;
- INC (ScrElPtr.OFS, 2) ;
- END ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Produces a message on the last line of the screen and sets MessageRead }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE Message (Contents : STRING) ;
-
- BEGIN
- SetBottomLine (Contents) ;
- MessageRead := (LENGTH (Contents) = 0) ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Produces an error beep (if allowed by Setup), writes an error message }
- { corresponding to the error number, on the last screen line and waits }
- { until the Escape key is pressed. }
- { If any macros are running, they are canceled. }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE ErrorMessage (ErrorNr : BYTE) ;
-
- VAR ErrorText : STRING [ColsOnScreen] ;
-
- BEGIN
- IF Config.Setup.SoundBell
- THEN BEGIN
- SOUND (880) ;
- DELAY (100) ;
- NOSOUND ;
- END ;
- CASE ErrorNr OF
- 1 : ErrorText := 'Not enough memory' ;
- 4 : ErrorText := 'Block too large for paste buffer' ;
- 5 : ErrorText := 'No block defined' ;
- 6 : ErrorText := 'Maximum macro length reached. End of define mode' ;
- 7 : ErrorText := 'File too large. Only partially read' ;
- 8 : ErrorText := 'File not found' ;
- 9 : ErrorText := 'Cyclic macro definition. Key ignored' ;
- 10 : ErrorText := 'Too many macros nested. Execution canceled' ;
- 11 : ErrorText := 'Word wrap mode must be on to do this' ;
- 12 : ErrorText := 'Position stack full' ;
- 13 : ErrorText := 'Position stack empty' ;
- 14 : CASE DosError OF
- 2 : ErrorText := 'Can not find COMMAND.COM ' ;
- 8 : ErrorText := 'Not enough memory to execute DOS command' ;
- ELSE ErrorText := 'DOS error ' + WordToString (DosError, 2) ;
- END ; { of case }
- 15 : ErrorText := 'String not found' ;
- 16 : ErrorText := 'Illegal file name' ;
- 17 : CASE DiskError OF
- 2 : ErrorText := 'File not found' ;
- 3 : ErrorText := 'Path not found' ;
- 5 : ErrorText := 'File access denied' ;
- 100 : ErrorText := 'Disk read error' ;
- 101 : ErrorText := 'Disk write error' ;
- 103 : ErrorText := 'File not open' ;
- 150 : ErrorText := 'Disk is write-protected' ;
- 152 : ErrorText := 'Drive not ready' ;
- 159 : ErrorText := 'Printer out of paper' ;
- 160 : ErrorText := 'Device write fault' ;
- ELSE ErrorText := 'I/O error ' + WordToString (DiskError, 0) ;
- END ; { of case }
- 18 : ErrorText := 'Macro execution interrupted' ;
- 19 : ErrorText := 'Bad or incompatible configuration file. Using default' ;
- 20 : ErrorText := 'Please enter a number' ;
- 21 : ErrorText := 'Number is too low' ;
- 22 : ErrorText := 'Number is too high' ;
- 23 : ErrorText := 'Bad or incompatible work file' ;
- END ; { of case }
- SetBottomLine (ErrorText + ' (press Esc)') ;
- REPEAT UNTIL ReadKeyNr = EscapeKey ;
- IF MacroStackpointer <> Inactive
- THEN BEGIN
- MacroStackpointer := Inactive ;
- Message ('Macro execution canceled') ;
- END
- ELSE Message ('') ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Like the DOS batch command, Pause displays the message 'Press any key to }
- { continue' and then waits until a key is pressed. }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE Pause ;
-
- VAR DummyKey : WORD ;
-
- BEGIN
- SetBottomLine ('Press any key to continue') ;
- DummyKey := ReadKeyNr ;
- EscPressed := (DummyKey = EscapeKey) ;
- SetBottomLine ('') ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Reads the result of the last I/O operation into the DiskError variable }
- { and produces an error message if an error has occurred. }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE CheckDiskError ;
-
- BEGIN
- DiskError := IORESULT ;
- IF DiskError <> 0 THEN ErrorMessage (17) ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Draws a frame on the text screen between (X1,Y1) and (X2,Y2) }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE PutFrame (X1, Y1, X2, Y2 : BYTE ; Border : STRING) ;
-
- VAR i : BYTE ;
-
- BEGIN
- CursorTo (X1, Y1) ; WRITE (Border [1]) ; { upper left corner }
- FOR i := SUCC (X1) TO PRED (X2) DO WRITE (Border [2]) ; { upper side }
- WRITE (Border [3]) ; { upper right corner }
- FOR i := SUCC (Y1) TO PRED (Y2) DO
- BEGIN
- CursorTo (X1, i) ; WRITE (Border [8]) ; { left side }
- CursorTo (X2, i) ; WRITE (Border [4]) ; { right side }
- END ;
- CursorTo (X1, Y2) ; WRITE (Border [7]) ; { lower right corner }
- FOR i := SUCC (X1) TO PRED (X2) DO WRITE (Border [6]) ; { lower side }
- WRITE (Border [5]) ; { lower left corner }
- END ;
-
- {-----------------------------------------------------------------------------}
- { Clears a rectangular screen area between (X1,Y1) and (X2,Y2). }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE ClearArea (X1, Y1, X2, Y2 : BYTE) ;
-
- VAR OldWindMax, OldWindMin : WORD ;
-
- BEGIN
- OldWindMax := WindMax ;
- OldWindMin := WindMin ;
- WINDOW (X1, Y1, X2, Y2) ;
- CLRSCR ;
- WINDOW (LO (OldWindMin) + 1, HI (OldWindMin) + 1,
- LO (OldWindMax) + 1, HI (OldWindMax) + 1) ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Clears the current workspace, resetting all variables. }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE ClearCurrentWs ;
-
- BEGIN
- WITH Workspace [CurrentWsnr] DO
- BEGIN
- Name := '' ;
- ChangesMade := FALSE ;
- GETTIME (LastTimeSaved [1], LastTimeSaved [2],
- LastTimeSaved [3], LastTimeSaved [4]) ;
- CurPos.Index := 1 ;
- CurPos.Linenr := 1 ;
- CurPos.Colnr := 1 ;
- MARK := Inactive ;
- FirstVisibleLine := CurPos ;
- FirstScreenCol := 1 ;
- VirtualColnr := 1 ;
- Buffer^ [1] := EF ;
- Buffersize := 1 ;
- PosStackPointer := Inactive ;
- END ;
- { make copy of current workspace equal to original }
- CurrentWs := Workspace [CurrentWsnr] ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Clears the keys in the keyboard buffer. }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE ClearKeyBuffer ;
-
- VAR DummyKey : CHAR ;
-
- BEGIN
- WHILE KEYPRESSED DO DummyKey := READKEY ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Checks if the Escape key has been pressed }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE CheckEsc ;
-
- BEGIN
- EscPressed := FALSE ;
- WHILE KEYPRESSED DO
- IF READKEY = ESC THEN EscPressed := TRUE ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Creates an empty history with lines of <LineLen> chars long }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE CreateHistory (VAR Hp : HistPtr ; LineLen : BYTE) ;
-
- VAR i : BYTE ;
-
- BEGIN
- NEW (Hp) ;
- FOR i := 1 TO MaxHistLength DO
- GETMEM (POINTER(Hp^.LINE [i]), LineLen + 1) ;
- Hp^.MaxLineLen := LineLen ;
- Hp^.Len := 0 ;
- Hp^.CurLine := 0 ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Adds a new string to a history, unless already present }
- {-----------------------------------------------------------------------------}
-
- PROCEDURE AddToHistory (Hp : HistPtr ; S : STRING) ;
-
- VAR i,j : BYTE ;
-
- BEGIN
- WITH Hp^ DO
- BEGIN
- { check if line already present in history }
- i := 1 ;
- WHILE (i < Len ) AND (S <> LINE [i]^) DO
- INC (i) ;
- IF (Len > 0) AND (S = LINE[i]^)
- THEN BEGIN
- { move this line to top of history }
- FOR j := i TO (Len-1) DO
- LINE[j]^ := LINE[j+1]^ ;
- LINE[Len]^ := S ;
- END
- ELSE BEGIN
- { add line to end of history }
- IF Len < MaxHistLength
- THEN { expand history }
- INC (Len)
- ELSE { history full: shift lines, losing the oldest one }
- FOR i := 1 TO (Len - 1) DO
- LINE [i]^ := LINE [i + 1]^ ;
- LINE [Len]^ := COPY (S, 1, MaxLineLen) ;
- END ;
- { set current line so that next PrevHistLine returns this line }
- CurLine := 0 ;
- END ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Returns the current history line }
- {-----------------------------------------------------------------------------}
-
- FUNCTION CurrentHistLine (Hp : HistPtr) : STRING ;
-
- BEGIN
- WITH Hp^ DO
- IF (Len = 0) OR (CurLine = 0)
- THEN CurrentHistLine := ''
- ELSE CurrentHistLine := LINE [CurLine]^ ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Returns the history line above the current one }
- {-----------------------------------------------------------------------------}
-
- FUNCTION NextHistLine (Hp : HistPtr) : STRING ;
-
- BEGIN
- WITH Hp^ DO
- BEGIN
- IF CurLine = Len
- THEN CurLine := 0
- ELSE INC (CurLine) ;
- NextHistLine := CurrentHistLine (Hp) ;
- END ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Returns the history line below the current one }
- {-----------------------------------------------------------------------------}
-
- FUNCTION PrevHistLine (Hp : HistPtr) : STRING ;
-
- BEGIN
- WITH Hp^ DO
- BEGIN
- IF CurLine = 0
- THEN CurLine := Len
- ELSE DEC (CurLine) ;
- PrevHistLine := CurrentHistLine (Hp) ;
- END ;
- END ;
-
- {-----------------------------------------------------------------------------}
- { Determines the left margin of the current line. Position P must be after }
- { the first non-space, otherwise the result is 1. }
- {-----------------------------------------------------------------------------}
-
- FUNCTION LeftMargin (VAR P : Position) : WORD ;
-
- VAR Counter : WORD ;
-
- BEGIN
- WITH CurrentWs DO
- BEGIN
- { look for first non-space on current line }
- Counter := 1 ;
- WHILE (Buffer^ [P.Index - P.Colnr + Counter] = ' ') AND
- (Counter <= P.Colnr) DO
- INC (Counter) ;
- IF (Counter > P.Colnr)
- THEN LeftMargin := 1
- ELSE LeftMargin := Counter ;
- END ; { of with }
- END ;
-
- {-----------------------------------------------------------------------------}
- { GetMem is redirected, to keep track of available memory. }
- {-----------------------------------------------------------------------------}
-
- {$IFDEF DEVELOP }
- PROCEDURE GetMem (VAR P : pointer ; Size : WORD ) ;
-
- BEGIN
- System.GetMem (P, Size) ;
- IF MEMAVAIL < MinMemAvail
- THEN MinMemAvail := MEMAVAIL ;
- END ;
- {$ENDIF }
-
- {-----------------------------------------------------------------------------}
-
- END.